﻿Imports System
Imports System.Text
Imports System.Drawing
Imports System.Windows.Forms
Imports System.Collections.Generic

''' <summary>
''' This AutoComplete item appears after dot
''' </summary>
Public Class MethodAutoCompleteItem
    Inherits AutoCompleteItem

    Private firstPart As String
    Private lowercaseText As String

    Public Sub New(text As String)
        MyBase.New(text)
        lowercaseText = Me.Text.ToLower()
    End Sub

    Public Overrides Function Compare(fragmentText As String) As CompareResult
        Dim i As Integer = fragmentText.LastIndexOf("."c)
        If i < 0 Then Return CompareResult.Hidden

        Dim lastPart As String = fragmentText.Substring(i + 1)
        firstPart = fragmentText.Substring(0, i)

        If lastPart = "" Then Return CompareResult.Visible
        If Text.StartsWith(lastPart, StringComparison.InvariantCultureIgnoreCase) Then Return CompareResult.VisibleAndSelected
        If lowercaseText.Contains(lastPart.ToLower()) Then Return CompareResult.Visible

        Return CompareResult.Hidden
    End Function

    Public Overrides Function GetTextForReplace() As String
        Return firstPart & "." & Text
    End Function
End Class

''' <summary>
''' AutoComplete item for code snippets
''' </summary>
''' <remarks>Snippet can contain special char ^ for caret position.</remarks>
Public Class SnippetAutoCompleteItem
    Inherits AutoCompleteItem

    Public Sub New(snippet As String)
        Text = snippet.Replace("\r", "").Replace(vbCr, "") '"\r",vbCr
        ToolTipTitle = "Code snippet:"
        ToolTipText = Text
    End Sub

    Public Overrides Function ToString() As String
        Return If(MenuText, Text.Replace("\n", " ").Replace(vbLf, " ").Replace("^", "")) '"\n",vbLf
    End Function

    Public Overrides Function GetTextForReplace() As String
        Return Text
    End Function

    Public Overrides Sub OnSelected(e As SelectedEventArgs)
        Dim tb = Parent.TargetControlWrapper

        If Not Me.Text.Contains("^") Then Return

        Dim text = tb.Text
        For i = Parent.Fragment.Start To text.Length - 1
            If text(i) = "^"c Then
                tb.SelectionStart = i
                tb.SelectionLength = 1
                tb.SelectedText = ""
                Return
            End If
        Next
    End Sub

    ''' <summary>
    ''' Compares fragment text with this item
    ''' </summary>
    Public Overrides Function Compare(fragmentText As String) As CompareResult
        If Text.StartsWith(fragmentText, StringComparison.InvariantCultureIgnoreCase) AndAlso Text <> fragmentText Then
            Return CompareResult.Visible
        End If
        Return CompareResult.Hidden
    End Function
End Class

''' <summary>
''' This class finds items by substring
''' </summary>
Public Class SubstringAutoCompleteItem
    Inherits AutoCompleteItem

    Protected ReadOnly lowercaseText As String
    Protected ReadOnly ignoreCase As Boolean

    Public Sub New(text As String, Optional ignoreCase As Boolean = True)
        MyBase.New(text)
        Me.ignoreCase = ignoreCase
        If ignoreCase Then lowercaseText = Me.Text.ToLower()
    End Sub

    Public Overrides Function Compare(fragmentText As String) As CompareResult
        If ignoreCase Then
            If lowercaseText.Contains(fragmentText.ToLower()) Then
                Return CompareResult.Visible
            End If
        Else
            If Text.Contains(fragmentText) Then
                Return CompareResult.Visible
            End If
        End If

        Return CompareResult.Hidden
    End Function
End Class

''' <summary>
''' This item draws multicolumn menu
''' </summary>
Public Class MulticolumnAutoCompleteItem
    Inherits SubstringAutoCompleteItem

    Public Property CompareBySubstring() As Boolean
    Public Property MenuTextByColumns() As String()
    Public Property ColumnWidth() As Integer()

    Public Sub New(menuTextByColumns As String(), insertingText As String, Optional compareBySubstring As Boolean = True, Optional ignoreCase As Boolean = True)
        MyBase.New(insertingText, ignoreCase)
        Me.CompareBySubstring = compareBySubstring
        Me.MenuTextByColumns = menuTextByColumns
    End Sub

    Public Overrides Function Compare(fragmentText As String) As CompareResult
        If CompareBySubstring Then Return MyBase.Compare(fragmentText)

        If ignoreCase Then
            If Text.StartsWith(fragmentText, StringComparison.InvariantCultureIgnoreCase) Then
                Return CompareResult.VisibleAndSelected
            End If
        ElseIf Text.StartsWith(fragmentText) Then
            Return CompareResult.VisibleAndSelected
        End If

        Return CompareResult.Hidden
    End Function

    Public Overrides Sub OnPaint(e As PaintItemEventArgs)
        If Me.ColumnWidth IsNot Nothing AndAlso Me.ColumnWidth.Length <> MenuTextByColumns.Length Then
            Throw New Exception("ColumnWidth.Length <> MenuTextByColumns.Length")
        End If

        Dim columnWidth As Integer() = Me.ColumnWidth
        If columnWidth Is Nothing Then
            columnWidth = New Integer(MenuTextByColumns.Length) {}
            Dim [step] As Single = e.TextRect.Width / MenuTextByColumns.Length
            For i = 0 To MenuTextByColumns.Length - 1
                columnWidth(i) = CInt([step])
            Next
        End If

        'draw columns
        Dim pen As Pen = Pens.Silver
        Dim x As Single = e.TextRect.X
        e.StringFormat.FormatFlags = e.StringFormat.FormatFlags Or StringFormatFlags.NoWrap

        Using brush = New SolidBrush(If(e.IsSelected, e.Colors.SelectedForeColor, e.Colors.ForeColor))
            For i = 0 To MenuTextByColumns.Length - 1
                Dim width As Object = columnWidth(i)
                Dim rect As New RectangleF(x, e.TextRect.Top, width, e.TextRect.Height)
                e.Graphics.DrawLine(pen, New PointF(x, e.TextRect.Top), New PointF(x, e.TextRect.Bottom))
                e.Graphics.DrawString(MenuTextByColumns(i), e.Font, brush, rect, e.StringFormat)
                x += width
            Next
        End Using
    End Sub
End Class